---
title: "Integrate Mastra in your Astro project | Frameworks"
description: A step-by-step guide to integrating Mastra with Astro.
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import Steps from "@site/src/components/Steps";
import StepItem from "@site/src/components/StepItem";

# Integrate Mastra in your Astro project

Mastra integrates with Astro, making it easy to:

- Build flexible APIs to serve AI-powered features
- Simplify deployment with a unified codebase for frontend and backend
- Take advantage of Astro's built-in [Actions](https://docs.astro.build/en/guides/actions/) or [Server Endpoints](https://docs.astro.build/en/guides/endpoints/#server-endpoints-api-routes) for efficient server-client workflows

Use this guide to scaffold and integrate Mastra with your Astro project.

<Tabs>
  <TabItem value="actions" label="Actions">

:::warning

This guide assumes you're using Astro's Actions with React and the Vercel adapter.

:::

  <Steps>

<StepItem>

Install the required packages:

<Tabs>
<TabItem value="npm" label="npm">

```bash copy
npm install mastra@beta @mastra/core@beta @mastra/libsql@beta @ai-sdk/openai
```

</TabItem>
<TabItem value="yarn" label="yarn">

```bash copy
yarn add mastra@beta @mastra/core@beta @mastra/libsql@beta @ai-sdk/openai
```

</TabItem>
<TabItem value="pnpm" label="pnpm">

```bash copy
pnpm add mastra@beta @mastra/core@beta @mastra/libsql@beta @ai-sdk/openai
```

</TabItem>
<TabItem value="bun" label="bun">

```bash copy
bun add mastra@beta @mastra/core@beta @mastra/libsql@beta @ai-sdk/openai
```

</TabItem>
</Tabs>

</StepItem>

<StepItem>

To integrate Mastra into your project, you have two options:

- Use the One-Liner

  Run the following command to quickly scaffold the default Weather agent with sensible defaults:

  ```bash copy
  npx mastra@beta init --default
  ```

  > See [mastra init](/reference/v1/cli/create-mastra) for more information.

- Use the Interactive CLI

  If you prefer to customize the setup, run the `init` command and choose from the options when prompted:

  ```bash copy
  npx mastra@beta init
  ```

Add the `dev` and `build` scripts to `package.json`:

```json title="package.json"
{
  "scripts": {
    ...
    "dev:mastra": "mastra dev",
    "build:mastra": "mastra build"
  }
}
```

</StepItem>

<StepItem>

Modify the `tsconfig.json` file in your project root:

```json title="tsconfig.json"
{
  ...
  "exclude": ["dist", ".mastra"]
}
```

</StepItem>

<StepItem>

Setup your API key in a `.env` file:

```bash title=".env" copy
OPENAI_API_KEY=<your-api-key>
```

</StepItem>

<StepItem>

Add `.mastra` and `.vercel` to your `.gitignore` file:

```bash title=".gitignore" copy
.mastra
.vercel
```

</StepItem>

<StepItem>

Astro uses Vite, which accesses environment variables via `import.meta.env` rather than `process.env`. As a result, the model constructor must explicitly receive the `apiKey` from the Vite environment like this:

```typescript title="src/mastra/agents/weather-agent.ts"
 import { createOpenAI } from "@ai-sdk/openai";

 const openai = createOpenAI({
   apiKey: import.meta.env?.OPENAI_API_KEY,
   compatibility: "strict"
 });
```

> More configuration details are available in the AI SDK docs. See [Provider Instance](https://ai-sdk.dev/providers/ai-sdk-providers/openai#provider-instance) for more information.

</StepItem>

<StepItem>

Start the Mastra Dev Server to expose your agents as REST endpoints:

<Tabs>
<TabItem value="npm" label="npm">

```bash copy
npm run dev:mastra
```

</TabItem>
<TabItem value="cli" label="CLI">

```bash copy
mastra dev:mastra
```

</TabItem>
</Tabs>

> Once running, your agents are available locally. See [Local Development Environment](/docs/v1/getting-started/studio) for more information.

</StepItem>

<StepItem>

With the Mastra Dev Server running, you can start your Astro site in the usual way.

</StepItem>

<StepItem>

Create an `actions` directory:

```bash copy
mkdir src/actions
```

</StepItem>

<StepItem>

Create a new Action, and add the example code:

```bash copy
touch src/actions/index.ts
```

```typescript title="src/actions/index.ts" showLineNumbers copy
import { defineAction } from "astro:actions";
import { z } from "astro:schema";

import { mastra } from "../mastra";

export const server = {
  getWeatherInfo: defineAction({
    input: z.object({
      city: z.string(),
    }),
    handler: async (input) => {
      const city = inputData.city;
      const agent = mastra.getAgent("weatherAgent");

      const result = await agent.generate(
        `What's the weather like in ${city}?`,
      );

      return result.text;
    },
  }),
};
```

</StepItem>

<StepItem>

Create a new Form component, and add the example code:

```bash copy
touch src/components/form.tsx
```

```typescript title="src/components/form.tsx" showLineNumbers copy
import { actions } from "astro:actions";
import { useState } from "react";

export const Form = () => {
  const [result, setResult] = useState<string | null>(null);

  async function handleSubmit(formData: FormData) {
    const city = formData.get("city")!.toString();
    const { data } = await actions.getWeatherInfo({ city });

    setResult(data || null);
  }

  return (
    <>
      <form action={handleSubmit}>
        <input name="city" placeholder="Enter city" required />
        <button type="submit">Get Weather</button>
      </form>
      {result && <pre>{result}</pre>}
    </>
  );
};
```

</StepItem>

<StepItem>

Create a new Page, and add the example code:

```bash copy
touch src/pages/test.astro
```

```astro title="src/pages/test.astro" showLineNumbers copy
---
import { Form } from '../components/form'
---

<h1>Test</h1>
<Form client:load />
```

> You can now navigate to `/test` in your browser to try it out.

Submitting **London** as the city would return a result similar to:

```plaintext
Agent response: The current weather in London is as follows:

- **Temperature:** 12.9°C (Feels like 9.7°C)
- **Humidity:** 63%
- **Wind Speed:** 14.7 km/h
- **Wind Gusts:** 32.4 km/h
- **Conditions:** Overcast

Let me know if you need more information!
```

</StepItem>

  </Steps>
  </TabItem>

  <TabItem value="server-endpoints" label="Server Endpoints">

:::warning

This guide assumes you're using Astro's Endpoints with React and the Vercel adapter, and your output is set to server.

:::

## Prerequisites

Before proceeding, ensure your Astro project is configured as follows:

- Astro React integration: [@astrojs/react](https://docs.astro.build/en/guides/integrations-guide/react/)
- Vercel adapter: [@astrojs/vercel](https://docs.astro.build/en/guides/integrations-guide/vercel/)
- `astro.config.mjs` is set to `output: "server"`

<Steps>

<StepItem>

Install the required packages:

<Tabs>
<TabItem value="npm" label="npm">

```bash copy
npm install mastra@beta @mastra/core@beta @mastra/libsql@beta @ai-sdk/openai
```

</TabItem>
<TabItem value="yarn" label="yarn">

```bash copy
yarn add mastra@beta @mastra/core@beta @mastra/libsql@beta @ai-sdk/openai
```

</TabItem>
<TabItem value="pnpm" label="pnpm">

```bash copy
pnpm add mastra@beta @mastra/core@beta @mastra/libsql@beta @ai-sdk/openai
```

</TabItem>
<TabItem value="bun" label="bun">

```bash copy
bun add mastra@beta @mastra/core@beta @mastra/libsql@beta @ai-sdk/openai
```

</TabItem>
</Tabs>

</StepItem>

<StepItem>

To integrate Mastra into your project, you have two options:

- Use the One-Liner

  Run the following command to quickly scaffold the default Weather agent with sensible defaults:

  ```bash copy
  npx mastra@beta init --default
  ```

  > See [mastra init](/reference/v1/cli/create-mastra) for more information.

- Use the Interactive CLI

  If you prefer to customize the setup, run the `init` command and choose from the options when prompted:

  ```bash copy
  npx mastra@beta init
  ```

Add the `dev` and `build` scripts to `package.json`:

```json title="package.json"
{
  "scripts": {
    ...
    "dev:mastra": "mastra dev",
    "build:mastra": "mastra build"
  }
}
```

</StepItem>

<StepItem>

Modify the `tsconfig.json` file in your project root:

```json title="tsconfig.json"
{
  ...
  "exclude": ["dist", ".mastra"]
}
```

</StepItem>

<StepItem>

Setup your API key in a `.env` file:

```bash title=".env" copy
OPENAI_API_KEY=<your-api-key>
```

</StepItem>

<StepItem>

Add `.mastra` to your `.gitignore` file:

```bash title=".gitignore" copy
.mastra
.vercel
```

</StepItem>

<StepItem>

Astro uses Vite, which accesses environment variables via `import.meta.env` rather than `process.env`. As a result, the model constructor must explicitly receive the `apiKey` from the Vite environment like this:

```typescript title="src/mastra/agents/weather-agent.ts"
 import { createOpenAI } from "@ai-sdk/openai";

 const openai = createOpenAI({
   apiKey: import.meta.env?.OPENAI_API_KEY,
   compatibility: "strict"
 });
```

> More configuration details are available in the AI SDK docs. See [Provider Instance](https://ai-sdk.dev/providers/ai-sdk-providers/openai#provider-instance) for more information.

</StepItem>

<StepItem>

Start the Mastra Dev Server to expose your agents as REST endpoints:

<Tabs>
<TabItem value="npm" label="npm">

```bash copy
npm run dev:mastra
```

</TabItem>
<TabItem value="cli" label="CLI">

```bash copy
mastra dev:mastra
```

</TabItem>
</Tabs>

> Once running, your agents are available locally. See [Local Development Environment](/docs/v1/getting-started/studio) for more information.

</StepItem>

<StepItem>

With the Mastra Dev Server running, you can start your Astro site in the usual way.

</StepItem>

<StepItem>

Create an `api` directory:

```bash copy
mkdir src/pages/api
```

</StepItem>

<StepItem>

Create a new Endpoint, and add the example code:

```bash copy
touch src/pages/api/test.ts
```

```typescript title="src/pages/api/test.ts" showLineNumbers copy
import type { APIRoute } from "astro";

import { mastra } from "../../mastra";

export const POST: APIRoute = async ({ request }) => {
  const { city } = await new Response(request.body).json();
  const agent = mastra.getAgent("weatherAgent");

  const result = await agent.generate(`What's the weather like in ${city}?`);

  return new Response(JSON.stringify(result.text));
};
```

</StepItem>

<StepItem>

Create a new Form component, and add the example code:

```bash copy
touch src/components/form.tsx
```

```typescript title="src/components/form.tsx" showLineNumbers copy
import { useState } from "react";

export const Form = () => {
  const [result, setResult] = useState<string | null>(null);

  async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();

    const formData = new FormData(event.currentTarget);
    const city = formData.get("city")?.toString();

    const response = await fetch("/api/test", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ city })
    });

    const text = await response.json();
    setResult(text);
  }

  return (
    <>
      <form onSubmit={handleSubmit}>
        <input name="city" placeholder="Enter city" required />
        <button type="submit">Get Weather</button>
      </form>
      {result && <pre>{result}</pre>}
    </>
  );
};
```

</StepItem>

<StepItem>

Create a new Page, and add the example code:

```bash copy
touch src/pages/test.astro
```

```astro title="src/pages/test.astro" showLineNumbers copy
---
import { Form } from '../components/form'
---

<h1>Test</h1>
<Form client:load />
```

> You can now navigate to `/test` in your browser to try it out.

Submitting **London** as the city would return a result similar to:

```plaintext
Agent response: The current weather in London is as follows:

- **Temperature:** 12.9°C (Feels like 9.7°C)
- **Humidity:** 63%
- **Wind Speed:** 14.7 km/h
- **Wind Gusts:** 32.4 km/h
- **Conditions:** Overcast

Let me know if you need more information!
```

</StepItem>

  </Steps>
  </TabItem>
</Tabs>

## Next Steps

- [Deployment | With Astro on Vercel](/docs/v1/deployment/web-framework#with-astro-on-vercel)
- [Monorepo Deployment](/docs/v1/deployment/monorepo)
